_require local "../../../../basis.smi"
_require "../../../../smlformat-lib.smi"
_require "../../../data/symbols/main/Loc.smi"
_require "../../../data/symbols/main/Symbol.smi"
_require "../../../data/symbols/main/RecordLabel.smi"
_require "../../../data/name/main/CodeLabel.smi"

_require local "../../../data/builtin/main/BuiltinPrimitive.ppg.smi"
_require "../../../data/types/main/Types.ppg.smi"
_require local "../../../compilerIRs/idcalc/main/IDCalc.ppg.smi"
_require "../../../data/runtimetypes/main/FFIAttributes.ppg.smi"
_require "../../../compilerIRs/absyn/main/AbsynConst.smi"
_require local "../../../compilerIRs/absyn/main/AbsynConstFormatter.smi"
_require "../../../compilerIRs/patterncalc/main/PatternCalc.ppg.smi"

structure TypedCalc =
  struct
    datatype idstatus
      = RECFUNID of Types.varInfo * int | VARID of Types.varInfo
    val format_idstatus
        : idstatus -> SMLFormat.FormatExpression.expression list
    val formatWithType_idstatus : idstatus
                                     -> SMLFormat.FormatExpression.expression 
                                          list
    datatype exnCon = EXEXN of Types.exExnInfo | EXN of Types.exnInfo
    val format_exnCon
        : exnCon -> SMLFormat.FormatExpression.expression list
    val formatWithType_exnCon : exnCon -> SMLFormat.FormatExpression.expression list
    datatype ffiTy
      = FFIBASETY of Types.ty * Loc.loc
      | FFIFUNTY of FFIAttributes.attributes option * ffiTy list * ffiTy list option * ffiTy list *
                    Loc.loc
      | FFIRECORDTY of (RecordLabel.label * ffiTy) list * Loc.loc
    val format_ffiTy
        : ffiTy -> SMLFormat.FormatExpression.expression list
    val formatWithType_ffiTy
        : ffiTy -> SMLFormat.FormatExpression.expression list
    type constant = AbsynConst.constant
    datatype tpexp
      = TPAPPM of {argExpList:tpexp list, funExp:tpexp, funTy:Types.ty,
                   loc:Loc.loc}
      | TPCASEM of {caseKind:PatternCalc.caseKind, expList:tpexp list,
                    expTyList:Types.ty list, loc:Loc.loc, ruleBodyTy:Types.ty,
                    ruleList:{args:tppat list, body:tpexp} list}
      | TPSWITCH of
        {
          exp : tpexp,
          expTy : Types.ty,
          ruleList : switch_rules,
          defaultExp : tpexp,
          ruleBodyTy : Types.ty,
          loc : Loc.loc
        }
      | TPCAST of (tpexp * Types.ty) * Types.ty * Loc.loc
      | TPCONSTANT of {const:constant, loc:Loc.loc, ty:Types.ty}
      | TPDATACONSTRUCT of {argExpOpt:tpexp option, con:Types.conInfo,
                            instTyList:Types.ty list option, loc:Loc.loc}
      | TPDYNAMICCASE of
        {
         groupListTerm : tpexp, 
         groupListTy : Types.ty, 
         dynamicTerm : tpexp,
         dynamicTy : Types.ty, 
         elemTy : Types.ty, 
         ruleBodyTy : Types.ty, 
         loc:Loc.loc }
      | TPDYNAMICEXISTTAPP of
        {existInstMap:tpexp, exp:tpexp, expTy:Types.ty,
         instTyList:Types.ty list, loc:Loc.loc}
      | TPERROR
      | TPEXNCONSTRUCT of {argExpOpt:tpexp option, exn:exnCon, loc:Loc.loc}
      | TPEXNTAG of {exnInfo:Types.exnInfo, loc:Loc.loc}
      | TPEXEXNTAG of {exExnInfo:Types.exExnInfo, loc:Loc.loc}
      | TPEXVAR of (Types.exVarInfo * Loc.loc)
      | TPFFIIMPORT of {ffiTy:ffiTy, loc:Loc.loc, funExp:tpffifun,
                        stubTy:Types.ty}
      | TPFOREIGNSYMBOL of {name:string, ty:Types.ty, loc:Loc.loc}
      | TPFOREIGNAPPLY of
        {
          funExp : tpexp,
          argExpList : tpexp list,
          attributes : FFIAttributes.attributes,
          resultTy : Types.ty option,
          loc : Loc.loc
        }
      | TPCALLBACKFN of
        {
          attributes : FFIAttributes.attributes,
          argVarList : Types.varInfo list,
          bodyExp : tpexp,
          resultTy : Types.ty option,
          loc : Loc.loc
        }
      | TPFNM of {argVarList:Types.varInfo list, bodyExp:tpexp,
                  bodyTy:Types.ty, loc:Loc.loc}
      | TPHANDLE of {exnVar:Types.varInfo, exp:tpexp, handler:tpexp,
                     resultTy:Types.ty, loc:Loc.loc}
      | TPCATCH of
        {
          catchLabel : FunLocalLabel.id,
          argVarList : Types.varInfo list,
          catchExp : tpexp,
          tryExp : tpexp,
          resultTy : Types.ty,
          loc : Loc.loc
        }
      | TPTHROW of
        {
          catchLabel : FunLocalLabel.id,
          argExpList : tpexp list,
          resultTy : Types.ty,
          loc : Loc.loc
        }
      | TPLET of {body:tpexp, decls:tpdecl list, loc:Loc.loc}
      | TPMODIFY of {elementExp:tpexp, elementTy:Types.ty, label:RecordLabel.label,
                     loc:Loc.loc, recordExp:tpexp, recordTy:Types.ty}
      | TPMONOLET of {binds:(Types.varInfo * tpexp) list, bodyExp:tpexp,
                      loc:Loc.loc}
      | TPOPRIMAPPLY of {argExp:tpexp, instTyList:Types.ty list, loc:Loc.loc,
                         oprimOp:Types.oprimInfo}
      | TPPOLY of {btvEnv:Types.btvEnv, constraints: Types.constraint list,
                   exp:tpexp, expTyWithoutTAbs:Types.ty, loc:Loc.loc}
      | TPPRIMAPPLY of {argExp:tpexp, instTyList:Types.ty list option,
                        loc:Loc.loc, primOp:Types.primInfo}
      | TPRAISE of {exp:tpexp, loc:Loc.loc, ty:Types.ty}
      | TPRECFUNVAR of {arity:int, var:Types.varInfo}
      | TPRECORD of {fields:tpexp RecordLabel.Map.map, loc:Loc.loc, recordTy:Types.ty RecordLabel.Map.map}
      | TPSELECT of {exp:tpexp, expTy:Types.ty, label:RecordLabel.label, loc:Loc.loc,
                     resultTy:Types.ty}
      | TPSIZEOF of Types.ty * Loc.loc
      | TPTAPP of {exp:tpexp, expTy:Types.ty, instTyList:Types.ty list,
                   loc:Loc.loc}
      | TPVAR of Types.varInfo
      | TPJOIN of {ty : Types.ty, args : tpexp * tpexp, argtys : Types.ty * Types.ty, 
                   isJoin:bool,
                   loc:Loc.loc}
      | TPDYNAMIC of {exp:tpexp, ty:Types.ty, elemTy:Types.ty, coerceTy:Types.ty, loc:Loc.loc}
      | TPDYNAMICIS of {exp:tpexp, ty:Types.ty, elemTy:Types.ty, coerceTy:Types.ty, loc:Loc.loc}
      | TPDYNAMICNULL of {ty:Types.ty, coerceTy:Types.ty, loc:Loc.loc}
      | TPDYNAMICTOP of {ty:Types.ty, coerceTy:Types.ty, loc:Loc.loc}
      | TPDYNAMICVIEW of {exp:tpexp, ty:Types.ty, elemTy:Types.ty, coerceTy:Types.ty, loc:Loc.loc}
      | TPREIFYTY of Types.ty * Loc.loc
    and tpffifun
      = TPFFIFUN of tpexp * Types.ty
      | TPFFIEXTERN of string
    and switch_rules =
        CONSTCASE of {const : constant, ty : Types.ty, body : tpexp} list
      | CONCASE of {con : Types.conInfo,
                    instTyList : Types.ty list option,
                    argVarOpt : Types.varInfo option,
                    body : tpexp} list
      | EXNCASE of {exn : exnCon,
                    argVarOpt : Types.varInfo option,
                    body : tpexp} list
    and tpdecl
      = TPEXD of Types.exnInfo * Loc.loc
      | TPEXNTAGD of {exnInfo:Types.exnInfo, varInfo:Types.varInfo} * Loc.loc
      | TPEXPORTEXN of Types.exnInfo
      | TPEXPORTVAR of {var : Types.exVarInfo, exp : tpexp}
      | TPEXTERNEXN of {path:Symbol.longsymbol, ty:Types.ty}
                        * Types.provider
      | TPBUILTINEXN of {path:Symbol.longsymbol, ty:Types.ty}
      | TPEXTERNVAR of {path:Symbol.longsymbol, ty:Types.ty}
                        * Types.provider
      | TPFUNDECL of {argTyList:Types.ty list, bodyTy:Types.ty,
                      funVarInfo:Types.varInfo,
                      ruleList:{args:tppat list, body:tpexp} list} list * 
                     Loc.loc
      | TPPOLYFUNDECL of
        {btvEnv: Types.btvEnv,
         constraints: Types.constraint list,
         recbinds:{argTyList:Types.ty list, bodyTy:Types.ty,
                   funVarInfo:Types.varInfo,
                   ruleList:{args:tppat list, body:tpexp} list} list,
         loc:Loc.loc}
      | TPVAL of (Types.varInfo * tpexp) * Loc.loc
      | TPVALPOLYREC of
        {btvEnv: Types.btvEnv,
         constraints: Types.constraint list,
         recbinds : {exp:tpexp, var:Types.varInfo} list, loc : Loc.loc}
      | TPVALREC of {exp:tpexp, var:Types.varInfo} list * Loc.loc
    and tppat
      = TPPATCONSTANT of constant * Types.ty * Loc.loc
      | TPPATDATACONSTRUCT of {argPatOpt:tppat option, conPat:Types.conInfo,
                               instTyList:Types.ty list option, loc:Loc.loc,
                               patTy:Types.ty}
      | TPPATERROR of Types.ty * Loc.loc
      | TPPATEXNCONSTRUCT of {argPatOpt:tppat option, exnPat:exnCon,
                              loc:Loc.loc, patTy:Types.ty}
      | TPPATLAYERED of {asPat:tppat, loc:Loc.loc, varPat:tppat}
      | TPPATRECORD of {fields:tppat RecordLabel.Map.map, loc:Loc.loc, recordTy:Types.ty}
      | TPPATVAR of Types.varInfo
      | TPPATWILD of Types.ty * Loc.loc 
    val tppatToLoc : tppat -> Loc.loc
    val format_tpexp
        : tpexp
          -> SMLFormat.FormatExpression.expression list
    val format_tpdecl
        : tpdecl
          -> SMLFormat.FormatExpression.expression list
    val format_tppat
        : tppat
          -> SMLFormat.FormatExpression.expression list
    val formatWithType_tpexp
        : tpexp
          -> SMLFormat.FormatExpression.expression list
    val formatWithType_tpdecl
        : tpdecl
          -> SMLFormat.FormatExpression.expression list
    val formatWithType_tppat
        : tppat
          -> SMLFormat.FormatExpression.expression list
  end
